module RAM(
    input [5:0] maddr,    // 地址输入，表示内存地址。由ALU提供
    input [31:0] mwdata,   // 32位的写数据输入，表示需要写入内存的数据。由REGs.rdata2提供
    input clk,             // 时钟信号
    input we,              // 写使能信号，当为高电平时允许写入操作。由CU.mwe提供
    input [3:0] mm,        // 4位的模式输入，用于选择内存操作模式。由CU.mm提供
    output [31:0] mdata    // 32位的数据输出，表示从内存读取的数据。
    );

    wire[31:0] tmp, tmp_b, tmp_h, tmp_bu, tmp_hu, tmp_in;
    //识别各类读写方式
    wire lb, lh, lw, lbu, lhu, sb, sh, sw;

    empty_ram myram(
        .a(maddr>>2),   // 地址右移两位，表示按字寻址
        .d(tmp_in),     // 写入数据
        .clk(clk),      // 时钟信号
        .we(we),        // 写使能信号
        .spo(tmp)       // 输出数据
    );
    
        
    // 根据模式选择信号mm来设置不同的控制信号
    assign lb = ~(|mm),                     // 0000：字节读取
        lh = ~(|mm[3:1])&mm[0],             // 0001：半字读取
        lw = ~(|mm[3:2])&mm[1]&~mm[0],      // 0010：字读取
        lbu = ~(|mm[3:2])&(&mm[1:0]),       // 0011：无符号字节读取
        lhu = ~mm[3]&mm[2]&~(|mm[1:0]),     // 0100：无符号半字读取
        sb = mm[3]&~(|mm[2:0]),             // 1000：字节写入
        sh = mm[3]&~(|mm[2:1])&mm[0],       // 1001：半字写入
        sw = mm[3]&~mm[2]&mm[1]&~mm[0];     // 1010：字写入

    // 数据扩展与截断，根据模式信号生成不同的数据形式
    assign tmp_b = {{24{tmp[7]}}, tmp[7:0]};     // 字节扩展（符号扩展）
    assign tmp_h = {{16{tmp[15]}}, tmp[15:0]};   // 半字扩展（符号扩展）
    assign tmp_bu = {24'b0, tmp[7:0]};           // 无符号字节扩展
    assign tmp_hu = {16'b0, tmp[15:0]};          // 无符号半字扩展
    
    // 根据控制信号选择最终输出数据
    assign mdata = lb ? tmp_b : 
                   lh ? tmp_h : 
                   lw ? tmp : 
                   lbu ? tmp_bu : 
                   lhu ? tmp_hu : 
                   32'b0;   // 默认输出为0

    // 写入数据，根据控制信号选择不同的数据形式进行写入
    assign tmp_in = ({24'b0, {8{sb}}} | {16'b0, {16{sh}}} | {32{sw}}) & mwdata;
    
    initial
        $monitor($time, ," RAM: mm=%b, maddr=%h, mwdata=%h, mdata=%h",mm, maddr, mwdata, mdata);
endmodule
